package health

import (
	"fmt"
	"os"
	"runtime"
	"strconv"
	"strings"
)

// SystemChecker 系统环境检查器
type SystemChecker struct {
	requirements SystemRequirements
}

// SystemRequirements 系统要求
type SystemRequirements struct {
	MinGoVersion   string
	MinMemoryMB    int64
	MinDiskSpaceMB int64
	RequiredPorts  []int
	RequiredDirs   []string
}

// SystemStatus 系统状态
type SystemStatus struct {
	OS              string          `json:"os"`
	Arch            string          `json:"arch"`
	GoVersion       string          `json:"go_version"`
	MemoryMB        int64           `json:"memory_mb"`
	DiskSpaceMB     int64           `json:"disk_space_mb"`
	AvailablePorts  []int           `json:"available_ports"`
	DirectoryStatus map[string]bool `json:"directory_status"`
	Checks          []CheckResult   `json:"checks"`
	Overall         CheckStatus     `json:"overall"`
}

// CheckResult 检查结果
type CheckResult struct {
	Name       string      `json:"name"`
	Status     CheckStatus `json:"status"`
	Message    string      `json:"message"`
	Details    interface{} `json:"details,omitempty"`
	Suggestion string      `json:"suggestion,omitempty"`
}

// CheckStatus 检查状态
type CheckStatus string

const (
	StatusPass    CheckStatus = "PASS"
	StatusWarning CheckStatus = "WARNING"
	StatusFail    CheckStatus = "FAIL"
	StatusSkip    CheckStatus = "SKIP"
)

// NewSystemChecker 创建系统检查器
func NewSystemChecker() *SystemChecker {
	return &SystemChecker{
		requirements: SystemRequirements{
			MinGoVersion:   "1.20",
			MinMemoryMB:    512,
			MinDiskSpaceMB: 100,
			RequiredPorts:  []int{8765, 8766, 8767},
			RequiredDirs:   []string{"data", "logs", "config"},
		},
	}
}

// CheckSystem 执行系统检查
func (sc *SystemChecker) CheckSystem() *SystemStatus {
	status := &SystemStatus{
		OS:              runtime.GOOS,
		Arch:            runtime.GOARCH,
		GoVersion:       runtime.Version(),
		DirectoryStatus: make(map[string]bool),
		Checks:          []CheckResult{},
	}

	// 执行各项检查
	sc.checkGoVersion(status)
	sc.checkMemory(status)
	sc.checkDiskSpace(status)
	sc.checkPorts(status)
	sc.checkDirectories(status)
	sc.checkPermissions(status)

	// 计算总体状态
	sc.calculateOverallStatus(status)

	return status
}

// checkGoVersion 检查Go版本
func (sc *SystemChecker) checkGoVersion(status *SystemStatus) {
	current := strings.TrimPrefix(runtime.Version(), "go")
	required := sc.requirements.MinGoVersion

	result := CheckResult{
		Name: "Go版本检查",
	}

	if compareVersion(current, required) >= 0 {
		result.Status = StatusPass
		result.Message = fmt.Sprintf("Go版本 %s 满足要求 (>= %s)", current, required)
	} else {
		result.Status = StatusFail
		result.Message = fmt.Sprintf("Go版本 %s 不满足要求 (>= %s)", current, required)
		result.Suggestion = fmt.Sprintf("请升级Go到 %s 或更高版本", required)
	}

	status.Checks = append(status.Checks, result)
}

// checkMemory 检查内存
func (sc *SystemChecker) checkMemory(status *SystemStatus) {
	// 获取系统内存信息（简化实现）
	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)

	// 估算可用内存（这里使用简化方法）
	availableMemMB := int64(1024) // 默认假设1GB可用内存

	status.MemoryMB = availableMemMB

	result := CheckResult{
		Name: "内存检查",
	}

	if availableMemMB >= sc.requirements.MinMemoryMB {
		result.Status = StatusPass
		result.Message = fmt.Sprintf("可用内存 %dMB 满足要求 (>= %dMB)",
			availableMemMB, sc.requirements.MinMemoryMB)
	} else {
		result.Status = StatusWarning
		result.Message = fmt.Sprintf("可用内存 %dMB 可能不足 (建议 >= %dMB)",
			availableMemMB, sc.requirements.MinMemoryMB)
		result.Suggestion = "建议释放内存或增加系统内存"
	}

	status.Checks = append(status.Checks, result)
}

// checkDiskSpace 检查磁盘空间
func (sc *SystemChecker) checkDiskSpace(status *SystemStatus) {
	// 获取当前目录磁盘空间
	diskSpaceMB := sc.getDiskSpace(".")
	status.DiskSpaceMB = diskSpaceMB

	result := CheckResult{
		Name: "磁盘空间检查",
	}

	if diskSpaceMB >= sc.requirements.MinDiskSpaceMB {
		result.Status = StatusPass
		result.Message = fmt.Sprintf("可用磁盘空间 %dMB 满足要求 (>= %dMB)",
			diskSpaceMB, sc.requirements.MinDiskSpaceMB)
	} else {
		result.Status = StatusFail
		result.Message = fmt.Sprintf("可用磁盘空间 %dMB 不足 (>= %dMB)",
			diskSpaceMB, sc.requirements.MinDiskSpaceMB)
		result.Suggestion = "请清理磁盘空间或选择其他存储位置"
	}

	status.Checks = append(status.Checks, result)
}

// checkPorts 检查端口可用性
func (sc *SystemChecker) checkPorts(status *SystemStatus) {
	availablePorts := []int{}

	result := CheckResult{
		Name: "端口可用性检查",
	}

	for _, port := range sc.requirements.RequiredPorts {
		if sc.isPortAvailable(port) {
			availablePorts = append(availablePorts, port)
		}
	}

	status.AvailablePorts = availablePorts

	if len(availablePorts) > 0 {
		result.Status = StatusPass
		result.Message = fmt.Sprintf("找到 %d 个可用端口: %v",
			len(availablePorts), availablePorts)
	} else {
		result.Status = StatusWarning
		result.Message = "所有预设端口都被占用"
		result.Suggestion = "系统将自动扫描其他可用端口"
	}

	status.Checks = append(status.Checks, result)
}

// checkDirectories 检查目录权限
func (sc *SystemChecker) checkDirectories(status *SystemStatus) {
	result := CheckResult{
		Name: "目录权限检查",
	}

	allOK := true
	for _, dir := range sc.requirements.RequiredDirs {
		canCreate := sc.canCreateDirectory(dir)
		status.DirectoryStatus[dir] = canCreate
		if !canCreate {
			allOK = false
		}
	}

	if allOK {
		result.Status = StatusPass
		result.Message = "所有必需目录都可以创建"
	} else {
		result.Status = StatusFail
		result.Message = "部分目录无法创建"
		result.Suggestion = "请检查目录权限或以管理员身份运行"
	}

	status.Checks = append(status.Checks, result)
}

// checkPermissions 检查文件权限
func (sc *SystemChecker) checkPermissions(status *SystemStatus) {
	result := CheckResult{
		Name: "文件权限检查",
	}

	// 测试创建临时文件
	tempFile := "temp_permission_test.tmp"
	if err := sc.testFilePermissions(tempFile); err != nil {
		result.Status = StatusFail
		result.Message = "文件读写权限不足"
		result.Suggestion = "请检查当前目录权限或以管理员身份运行"
		result.Details = err.Error()
	} else {
		result.Status = StatusPass
		result.Message = "文件读写权限正常"
		// 清理测试文件
		os.Remove(tempFile)
	}

	status.Checks = append(status.Checks, result)
}

// calculateOverallStatus 计算总体状态
func (sc *SystemChecker) calculateOverallStatus(status *SystemStatus) {
	hasFailure := false
	hasWarning := false

	for _, check := range status.Checks {
		switch check.Status {
		case StatusFail:
			hasFailure = true
		case StatusWarning:
			hasWarning = true
		}
	}

	if hasFailure {
		status.Overall = StatusFail
	} else if hasWarning {
		status.Overall = StatusWarning
	} else {
		status.Overall = StatusPass
	}
}

// 辅助函数

// compareVersion 比较版本号
func compareVersion(current, required string) int {
	currentParts := strings.Split(current, ".")
	requiredParts := strings.Split(required, ".")

	maxLen := len(currentParts)
	if len(requiredParts) > maxLen {
		maxLen = len(requiredParts)
	}

	for i := 0; i < maxLen; i++ {
		var currentPart, requiredPart int

		if i < len(currentParts) {
			currentPart, _ = strconv.Atoi(currentParts[i])
		}
		if i < len(requiredParts) {
			requiredPart, _ = strconv.Atoi(requiredParts[i])
		}

		if currentPart > requiredPart {
			return 1
		} else if currentPart < requiredPart {
			return -1
		}
	}

	return 0
}

// getDiskSpace 获取磁盘空间（简化实现）
func (sc *SystemChecker) getDiskSpace(path string) int64 {
	// 简化实现，返回固定值
	// 实际实现需要调用系统API
	return 1024 // 假设1GB可用空间
}

// isPortAvailable 检查端口是否可用
func (sc *SystemChecker) isPortAvailable(port int) bool {
	// 这里可以复用之前实现的端口检查逻辑
	// 简化实现
	return port != 80 && port != 443 // 假设80和443被占用
}

// canCreateDirectory 检查是否可以创建目录
func (sc *SystemChecker) canCreateDirectory(dir string) bool {
	// 尝试创建目录
	if err := os.MkdirAll(dir, 0755); err != nil {
		return false
	}

	// 尝试删除测试目录（如果是新创建的）
	if info, err := os.Stat(dir); err == nil && info.IsDir() {
		// 检查目录是否为空，如果为空则删除
		if entries, err := os.ReadDir(dir); err == nil && len(entries) == 0 {
			os.Remove(dir)
		}
	}

	return true
}

// testFilePermissions 测试文件权限
func (sc *SystemChecker) testFilePermissions(filename string) error {
	// 尝试创建文件
	file, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("无法创建文件: %v", err)
	}
	defer file.Close()

	// 尝试写入
	if _, err := file.WriteString("test"); err != nil {
		return fmt.Errorf("无法写入文件: %v", err)
	}

	// 尝试读取
	if _, err := os.ReadFile(filename); err != nil {
		return fmt.Errorf("无法读取文件: %v", err)
	}

	return nil
}
